package awareness;

import awareness.defaults.MIEvent;
import events.EventHandler;

/**
* @brief Clase que implementa un conector para el servicio de metainformacion
* @author Carlos Rodriguez Dominguez
* @date 23/11/2008
*
* Implementacion de un conector para el servicio de metainformacion. Se encarga
* del envio automatico de eventos y del acceso a los datos del servicio de
* metainformacion. Previamente al uso de esta clase debera crearse una instancia
* de @see EventHandler y de @see MI_client. Con MI_client se debera escoger una
* aplicacion y un usuario valido para esta aplicacion.
*/
public class MIServiceConnector extends events.ListeningObject {
	
	/**
	* Hebra "policia". Se encarga de tomar los usuarios no actualizados y si han
	* pasado un tiempo demasiado grande sin actualizarse, entonces son desconectados
	*
	* @author Carlos Rodriguez Dominguez
	* @date 2/12/2008
	*/
	private class PoliceThread extends Thread{
		/**
		* Constructor
		*
		* @param r Referencia a la instancia de MIServiceConnector
		*/	
		public PoliceThread()
		{
			super();
		}
		
		/**
		* Reimplementacion del metodo "run" de la
		* superclase.
		*/
		@Override
		public void run()
		{
			String[] lu;
			while(true)
			{
				lu = mi_client.get_data_accessor().non_updated_users(application);
														
				for (int i=0; i<lu.length; i++)
				{
					mi_client.get_data_accessor().disconnect_user(application, lu[i]);
					
					MIEvent evento = new MIEvent();
					evento.member_value("mi_type", MIEvent.DISCONNECT);
					evento.member_value("application", application);
					evento.member_value("user", lu[i]);

					handler.push(evento);
				}
				
				try {
					Thread.sleep(60000); //60 segundos
				} catch (InterruptedException e) {
				}
			}
		}
	}

	/**
	* Hebra encargada de enviar eventos indicando que el usuario actual
	* esta conectado (actualiza su marca de tiempo en el sistema).
	*
	* @author Carlos Rodriguez Dominguez
	* @date 2/12/2008
	*/
	private class KeepAliveThread extends Thread {
		/**
		* Constructor
		*
		* @param r Referencia a la instancia de MIServiceConnector
		*/
		public KeepAliveThread()
		{
			super();
		}
		
		/**
		* Reimplementacion del metodo "run" de la
		* superclase.
		*/
		@Override
		public void run()
		{
			while(true)
			{
				if (connected)
				{
					mi_client.get_data_accessor().update_user_time(application, user);
					try {
						Thread.sleep(10000);
					} catch (InterruptedException e) {
					}
				}
				else
				{
					try {
						Thread.sleep(20000);
					} catch (InterruptedException e) {
					}
				}
			}
		}
	}
	
	private String user; /**< Usuario */
	private String role; /**< Rol actual del usuario */
	private String password; /**< Clave asociada al usuario */
	private String application; /**< Nombre de la aplicacion */
	private boolean login_allowed; /**< Para comprobar si se permite conectar al usuario actual */
	private boolean connected; /**< Comprueba si el usuario esta conectado */
	private EventHandler handler; /**< Manejador de eventos asociado al conector */
	private MIClient mi_client; /**< Cliente para el servicio de metainformacion */
	private KeepAliveThread keep_alive_thread; /**< Hebra que actualiza la marca de tiempo del usuario */
	private PoliceThread police_thread; /**< Hebra que desconecta los usuarios no actualizados */
	
	/**
	* Constructor
	*
	* @param app Aplicacion
	* @param u Usuario
	* @param pass Clave
	* @param h Manejador de eventos que se asociara al conector
	* @param mc Cliente de metainformacion para el servicio
	*/
	public MIServiceConnector(String app, String u, String pass, 
						EventHandler h, MIClient mc)
	{
		user = u;
		password = pass;
		application = app;
		role = null;
		handler = h;
		mi_client = mc;
		login_allowed = false;
		connected = false;
		keep_alive_thread = new KeepAliveThread();
		police_thread = new PoliceThread();
		
		police_thread.start(); //inicia la hebra policia
	}
	
	/**
	* Intenta loguearse en el sistema. Si se permite el login, entonces se admitira
	* llamar al metodo "connect_user" convenientemente.
	*
	* @return Metainformacion de la conexion. Si ocurrio algun error, entonces
	*         el campo error_message sera distinto a NULL y contendra el mensaje
	*         de error producido por el sistema.
	*/
	public collaboration.MIConnection login()
	{
		collaboration.MIConnection con = mi_client.get_data_accessor().login(application, user, password);
		if (con.error_message.equals("")) login_allowed = true;
		else login_allowed = false;
		return con;
	}
	
	/**
	* Comprueba si se poseen permisos de administracion
	*
	* @return True si se poseen permisos de administracion o False en caso contrario
	*/
	public boolean admin()
	{
		return mi_client.get_data_accessor().user_info(application, user).is_admin;
	}
	
	/**
	* Conecta al usuario en el servicio de metainformacion.
	*
	* @return Rol actual del usuario o NULL si no pudo conectarse
	*
	* @pre Debe llamarse al metodo "login" convenientemente
	* @post Se envia un evento distribuido con los siguientes campos: 
	*		- type = (PortableInteger)MI_EVENT_TYPE  (@see MIEvent.h)
	*       - mi_type = (PortableInteger)LOGIN
	*		- application = (char*)this->application
	*		- user = (char*)this->user
	*		- role = (char*)this->role);
	*/
	public String connect_user()
	{
		if (login_allowed)
		{
			role = mi_client.get_data_accessor().connect_user(application, user);
		
			//se distribuye el evento de login si no hubo error
			if (role != null)
			{
				MIEvent evento = new MIEvent();
				evento.member_value("mi_type", MIEvent.LOGIN);
				evento.member_value("application", application);
				evento.member_value("user", user);
				evento.member_value("role", role);
			
				handler.push(evento);
				
				keep_alive_thread.start(); //se inicia la hebra keep_alive
			}
			
			connected = true;
		
			return role;
		}
		else return null;
	}
	
	/**
	* Desconecta al usuario del servicio de metainformacion
	*
	* @post Se envia un evento distribuido con los siguientes campos: 
	*		- type = (PortableInteger)MI_EVENT_TYPE  (@see MIEvent.h) 
	* 		- mi_type = (PortableInteger)DISCONNECT
	*		- application = (char*)this->application
	*		- user = (char*)this->user
	*/
	public void disconnect_user()
	{
		if (connected)
		{
			connected = false;
			role = null;
			login_allowed = false;
			
			mi_client.get_data_accessor().disconnect_user(application, user);
			
			MIEvent evento = new MIEvent();
			evento.member_value("mi_type", MIEvent.DISCONNECT);
			evento.member_value("application", application);
			evento.member_value("user", user);

			handler.push(evento);
			
			keep_alive_thread.interrupt();
		}
	}
	
	/**
	* Cambia el rol actual del usuario
	*
	* @param newrole Nuevo rol actual del usuario
	* @return Metainformacion de la conexion. Si hubo algun error, entonces
	*         el campo error_message sera distinto a NULL.
	*
	* @post Se envia un evento distribuido con los siguientes campos:  
	*		- type = (PortableInteger)MI_EVENT_TYPE  (@see MIEvent.h)
	* 		- mi_type = (PortableInteger)USER_ROLE_CHANGED
	*		- application = (char*)this->application
	*		- user = (char*)this->user
	*		- role = (char*)this->role
	*/
	public collaboration.MIConnection change_connected_user_role(String newrole)
	{
		collaboration.MIConnection con = mi_client.get_data_accessor().
		change_connected_user_role(application, user, newrole);

		//distribuir el evento en caso de no haber error
		if (con.error_message.equals(""))
		{
			role = newrole;
			
			MIEvent evento = new MIEvent();
			evento.member_value("mi_type", MIEvent.USER_ROLE_CHANGED);
			evento.member_value("application", application);
			evento.member_value("user", user);
			evento.member_value("role", role);
			
			handler.push(evento);
		}
		
		return con;
	}
	
	/**
	* Obtiene una lista con los nombres de los usuarios asociados
	* a un rol especifico
	*
	* @param role_name Rol
	* @return Lista con los nombres de los usuarios
	*/
	public String[] role_users(String role_name)
	{
		return mi_client.get_data_accessor().role_users(application, role_name);
	}
	
	/**
	* Obtiene una lista con los nombres de los usuarios asociados
	* al rol actual
	*
	* @return Lista con los nombres de los usuarios
	*/
	public String[] role_users()
	{
		return mi_client.get_data_accessor().role_users(application, role);
	}
	
	/**
	* Obtiene los usuarios del sistema
	*
	* @return Lista con la metainformacion de los usuarios
	*/
	public collaboration.MIUser[] users_info()
	{
		return mi_client.get_data_accessor().users_info(application);
	}
	
	/**
	* Obtiene los roles del sistema
	*
	* @return Lista con la metainformacion de los roles
	*/
	public collaboration.MIRole[] roles_info()
	{
		return mi_client.get_data_accessor().roles_info(application);
	}
	
	/**
	* Obtiene la metainformacion del usuario
	*
	* @return Metainformacion del usuario
	*/
	public collaboration.MIUser user_info()
	{
		return mi_client.get_data_accessor().user_info(application, user);
	}
	
	/**
	* Obtiene la metainformacion de un usuario
	* 
	* @param user_name Nombre de usuario
	* @return Metainformacion del usuario
	*/
	public collaboration.MIUser user_info(String user_name)
	{
		return mi_client.get_data_accessor().user_info(application, user_name);
	}
	
	/**
	* Obtiene la metainformacion del rol actual
	*
	* @return Metainformacion del rol actual
	*/
	public collaboration.MIRole role_info()
	{
		return mi_client.get_data_accessor().role_info(application, role);
	}
	
	/**
	* Obtiene la metainformacion de un rol
	*
	* @param role_name Nombre del rol
	* @return Metainformacion del rol
	*/
	public collaboration.MIRole role_info(String role_name)
	{
		return mi_client.get_data_accessor().role_info(application, role_name);
	}
	
	/**
	* Obtiene la metainformacion de los usuarios conectados
	*
	* @return Lista con la metainformacion de los usuarios conectados
	*/
	public collaboration.MIUser[] connected_users()
	{
		return mi_client.get_data_accessor().connected_users_info(application);
	}
	
	/**
	* Obtiene los componentes
	*
	* @return Lista con los nombres de los componentes
	*/
	public String[] components()
	{
		return mi_client.get_data_accessor().application_components(application);
	}
	
	/**
	* Obtiene la metainformacion de los roles permitidos
	*
	* @return Metainformacion de los roles permitidos
	*/
	public collaboration.MIRole[] allowed_roles()
	{
		return mi_client.get_data_accessor().allowed_roles(application, user);
	}

	/**
	* Obtiene la metainformacion de los roles permitidos para
	* un usuario concreto.
	*
	* @param user_name Nombre del usuario
	* @return Metainformacion de los roles permitidos
	*/
	public collaboration.MIRole[] allowed_roles(String user_name)
	{
		return mi_client.get_data_accessor().allowed_roles(application, user_name);
	}
	
	/**
	* Asigna un nivel de permisos para un usuario y un componente
	*
	* @param user_name Nombre del usuario
	* @param comp Nombre del componente
	* @param level Nivel de permisos
	* @return True si se pudo asignar el nivel de permisos. False en
	*         caso contrario.
	*
	* @post Se envia un evento distribuido con los siguientes campos:  
	*		- type = (PortableInteger)MI_EVENT_TYPE  (@see MIEvent.h)
	*		- mi_type = (PortableInteger)USER_COMPONENT_PERMISSIONS_CHANGE
	*		- application = (char*)this->application
	*		- user = (char*)user_name
	*		- component = (char*)comp
	*/
	public boolean set_user_component_permissions(String user_name, String comp, int level)
	{
		boolean correcto = mi_client.get_data_accessor().
		set_user_component_permissions(application, user_name, comp, level);
		
		if (correcto) //distribuir evento
		{
			MIEvent evento = new MIEvent();
			evento.member_value("mi_type", MIEvent.USER_COMPONENT_PERMISSIONS_CHANGE);
			evento.member_value("application", application);
			evento.member_value("user", user_name);
			evento.member_value("component", comp);
			
			handler.push(evento);
		}
		
		return correcto;
	}
	
	/**
	* Asigna un nivel de permisos para el usuario actual y un componente
	*
	* @param comp Nombre del componente
	* @param level Nivel de permisos
	* @return True si se pudo asignar el nivel de permisos. False en
	*         caso contrario.
	*
	* @post Se envia un evento distribuido con los siguientes campos:  
	*		- type = (PortableInteger)MI_EVENT_TYPE  (@see MIEvent.h)
	*		- mi_type = (PortableInteger)USER_COMPONENT_PERMISSIONS_CHANGE
	*		- application = (char*)this->application
	*		- user = (char*)this->user
	*		- component = (char*)comp
	*/
	public boolean set_user_component_permissions(String comp, int level)
	{
		boolean correcto = mi_client.get_data_accessor().
		set_user_component_permissions(application, user, comp, level);
		
		if (correcto) //distribuir evento
		{
			MIEvent evento = new MIEvent();
			evento.member_value("mi_type", MIEvent.USER_COMPONENT_PERMISSIONS_CHANGE);
			evento.member_value("application", application);
			evento.member_value("user", user);
			evento.member_value("component", comp);
			
			handler.push(evento);
		}
		
		return correcto;
	}
	
	/**
	* Asigna un nivel de permisos para un rol y un componente
	*
	* @param role_name Nombre del rol
	* @param comp Nombre del componente
	* @param level Nivel de permisos
	* @return True si se pudo asignar el nivel de permisos. False en
	*         caso contrario.
	*
	* @post Se envia un evento distribuido con los siguientes campos:  
	*		- type = (PortableInteger)MI_EVENT_TYPE  (@see MIEvent.h)
	*		- mi_type = (PortableInteger)ROLE_COMPONENT_PERMISSIONS_CHANGE
	*		- application = (char*)this->application
	*		- role = (char*)role_name
	*		- component = (char*)comp
	*/
	public boolean set_role_component_permissions(String role_name, String comp, int level)
	{
		boolean correcto = mi_client.get_data_accessor().
		set_role_component_permissions(application, role_name, comp, level);
		
		if (correcto) //distribuir evento
		{
			MIEvent evento = new MIEvent();
			evento.member_value("mi_type", MIEvent.ROLE_COMPONENT_PERMISSIONS_CHANGE);
			evento.member_value("application", application);
			evento.member_value("role", role_name);
			evento.member_value("component", comp);
			
			handler.push(evento);
		}
		
		return correcto;
	}
	
	/**
	* Asigna un nivel de permisos para el rol actual y un componente
	*
	* @param comp Nombre del componente
	* @param level Nivel de permisos
	* @return True si se pudo asignar el nivel de permisos. False en
	*         caso contrario.
	*
	* @post Se envia un evento distribuido con los siguientes campos:  
	*		- type = (PortableInteger)MI_EVENT_TYPE  (@see MIEvent.h)
	*		- mi_type = (PortableInteger)ROLE_COMPONENT_PERMISSIONS_CHANGE
	*		- application = (char*)this->application
	*		- role = (char*)this->role
	*		- component = (char*)comp
	*/
	public boolean set_role_component_permissions(String comp, int level)
	{
		if (role != null)
		{
			boolean correcto = mi_client.get_data_accessor().
											set_role_component_permissions(application, role, comp, level);
										
			if (correcto) //distribuir evento
			{
				MIEvent evento = new MIEvent();
				evento.member_value("mi_type", MIEvent.ROLE_COMPONENT_PERMISSIONS_CHANGE);
				evento.member_value("application", application);
				evento.member_value("role", role);
				evento.member_value("component", comp);

				handler.push(evento);
			}
		
			return correcto;	
		}
		
		else return false;
	}
	
	/**
	* Obtiene el nivel de permisos para un componente y el usuario actual
	*
	* @param comp Nombre del componente
	* @return Nivel de permisos
	*/
	public int get_user_component_permissions(String comp)
	{
		return mi_client.get_data_accessor().get_user_component_permissions(application, user, comp);
	}

	/**
	* Obtiene el nivel de permisos para un componente y un usuario
	*
	* @param user_name Nombre del usuario
	* @param comp Nombre del componente
	* @return Nivel de permisos
	*/
	public int get_user_component_permissions(String user_name, String comp)
	{
		return mi_client.get_data_accessor().get_user_component_permissions(application, user_name, comp);
	}

	/**
	* Obtiene el nivel de permisos para un componente y el rol actual
	*
	* @param comp Nombre del componente
	* @return Nivel de permisos
	*/
	public int get_role_component_permissions(String comp)
	{
		return mi_client.get_data_accessor().get_role_component_permissions(application, role, comp);
	}

	/**
	* Obtiene el nivel de permisos para un componente y un rol
	*
	* @param role_name Nombre del rol
	* @param comp Nombre del componente
	* @return Nivel de permisos
	*/
	public int get_role_component_permissions(String role_name, String comp)
	{
		return mi_client.get_data_accessor().get_role_component_permissions(application, role_name, comp);
	}

	/**
	* Crea un nuevo usuario para el sistema
	*
	* @param user_name Nombre de usuario
	* @param pass Clave
	* @param default_role Rol por defecto para el usuario
	* @param is_admin Indica si es un administrador o no
	* @return True si pudo crearse el usuario. False en caso contrario.
	*
	* @post Se envia un evento distribuido con los siguientes campos:  
	*		- type = (PortableInteger)MI_EVENT_TYPE  (@see MIEvent.h)
	*		- mi_type = (PortableInteger)NEW_USER
	*		- application = (char*)this->application
	*		- user = (char*)user_name
	*/
	public boolean new_user(String user_name, String pass, 
							String default_role, boolean is_admin)
	{
		boolean correcto = mi_client.get_data_accessor().
		new_user(application, user_name, pass, default_role, is_admin);
	
		if (correcto) //distribuir evento
		{
			MIEvent evento = new MIEvent();
			evento.member_value("mi_type", MIEvent.NEW_USER);
			evento.member_value("application", application);
			evento.member_value("user", user_name);
			
			handler.push(evento);
		}
		
		return correcto;
	}

	/**
	* Crea un nuevo rol para el sistema
	*
	* @param role_name Nombre del rol
	* @return True si pudo crearse el rol. False en caso contrario.
	*
	* @post Se envia un evento distribuido con los siguientes campos:  
	*		- type = (PortableInteger)MI_EVENT_TYPE  (@see MIEvent.h)
	*		- mi_type = (PortableInteger)NEW_ROLE
	*		- application = (char*)this->application
	*		- role = (char*)role_name
	*/
	public boolean new_role(String role_name)
	{
		boolean correcto = mi_client.get_data_accessor().new_role(application, role_name);
		
		if (correcto) //distribuir evento
		{
			MIEvent evento = new MIEvent();
			evento.member_value("mi_type", MIEvent.NEW_ROLE);
			evento.member_value("application", application);
			evento.member_value("role", role_name);

			handler.push(evento);
		}

		return correcto;
	}

	/**
	* Crea un nuevo rol permitido para un usuario
	*
	* @param user_name Nombre del usuario
	* @param role_name Nombre del nuevo rol permitido
	* @return True si pudo crearse el nuevo rol permitido. False
	*         en caso contrario.
	*
	* @post Se envia un evento distribuido con los siguientes campos:  
	*		- type = (PortableInteger)MI_EVENT_TYPE  (@see MIEvent.h)
	*		- mi_type = (PortableInteger)NEW_ALLOWED_ROLE
	*		- application = (char*)this->application
	*		- user = (char*)user_name
	*		- role = (char*)role_name
	*/
	public boolean new_user_allowed_role(String user_name, String role_name)
	{
		boolean correcto = mi_client.get_data_accessor().
		new_user_allowed_role(application, user_name, role_name);
		
		if (correcto) //distribuir evento
		{
			MIEvent evento = new MIEvent();
			evento.member_value("mi_type", MIEvent.NEW_ALLOWED_ROLE);
			evento.member_value("application", application);
			evento.member_value("user", user_name);
			evento.member_value("role", role_name);
			
			handler.push(evento);
		}
		
		return correcto;
	}
	
	/**
	* Crea un nuevo rol permitido para el usuario
	*
	* @param role_name Nombre del nuevo rol permitido
	* @return True si pudo crearse el nuevo rol permitido. False
	*         en caso contrario.
	*
	* @post Se envia un evento distribuido con los siguientes campos:  
	*		- type = (PortableInteger)MI_EVENT_TYPE  (@see MIEvent.h)
	*		- mi_type = (PortableInteger)NEW_ALLOWED_ROLE
	*		- application = (char*)this->application
	*		- user = (char*)this->user
	*		- role = (char*)role_name
	*/
	public boolean new_user_allowed_role(String role_name)
	{
		boolean correcto = mi_client.get_data_accessor().
		new_user_allowed_role(application, user, role_name);
		
		if (correcto) //distribuir evento
		{
			MIEvent evento = new MIEvent();
			evento.member_value("mi_type", MIEvent.NEW_ALLOWED_ROLE);
			evento.member_value("application", application);
			evento.member_value("user", user);
			evento.member_value("role", role_name);
			
			handler.push(evento);
		}
		
		return correcto;
	}

	/**
	* Elimina un rol permitido para un usuario
	*
	* @param user_name Nombre del usuario
	* @param role_name Nombre del rol a eliminar
	* @return True si pudo eliminarse el rol permitido. False
	*         en caso contrario.
	*
	* @post Se envia un evento distribuido con los siguientes campos:  
	*		- type = (PortableInteger)MI_EVENT_TYPE  (@see MIEvent.h)
	*		- mi_type = (PortableInteger)REMOVE_ALLOWED_ROLE
	*		- application = (char*)this->application
	*		- user = (char*)user_name
	*		- role = (char*)role_name
	*/
	public boolean remove_allowed_user_role(String user_name, String role_name)
	{
		boolean correcto = mi_client.get_data_accessor().
		remove_allowed_user_role(application, user_name, role_name);
				
		if (correcto) //distribuir evento
		{
			MIEvent evento = new MIEvent();
			evento.member_value("mi_type", MIEvent.REMOVE_ALLOWED_ROLE);
			evento.member_value("application", application);
			evento.member_value("user", user_name);
			evento.member_value("role", role_name);
			
			handler.push(evento);
		}
		
		return correcto;
	}
	
	/**
	* Elimina un rol permitido para el usuario
	*
	* @param role_name Nombre del rol a eliminar
	* @return True si pudo eliminarse el rol permitido. False
	*         en caso contrario.
	*
	* @post Se envia un evento distribuido con los siguientes campos:  
	*		- type = (PortableInteger)MI_EVENT_TYPE  (@see MIEvent.h)
	*		- mi_type = (PortableInteger)REMOVE_ALLOWED_ROLE
	*		- application = (char*)this->application
	*		- user = (char*)this->user
	*		- role = (char*)role_name
	*/
	public boolean remove_allowed_user_role(String role_name)
	{
		boolean correcto = mi_client.get_data_accessor().
		remove_allowed_user_role(application, user, role_name);
		
		if (correcto) //distribuir evento
		{
			MIEvent evento = new MIEvent();
			evento.member_value("mi_type", MIEvent.REMOVE_ALLOWED_ROLE);
			evento.member_value("application", application);
			evento.member_value("user", user);
			evento.member_value("role", role_name);
			
			handler.push(evento);
		}
		
		return correcto;
	}
	
	/**
	* Elimina un usuario del sistema
	*
	* @param user_name Nombre del usuario
	* @return True si se pudo eliminar el usuario. False en caso contrario.
	*
	* @post Se envia un evento distribuido con los siguientes campos:  
	*		- type = (PortableInteger)MI_EVENT_TYPE  (@see MIEvent.h)
	*		- mi_type = (PortableInteger)REMOVE_USER
	*		- application = (char*)this->application
	*		- user = (char*)user_name
	*/
	public boolean remove_user(String user_name)
	{
		boolean correcto = mi_client.get_data_accessor().remove_user(application, user_name);
		
		if (correcto) //distribuir evento
		{
			MIEvent evento = new MIEvent();
			evento.member_value("mi_type", MIEvent.REMOVE_USER);
			evento.member_value("application", application);
			evento.member_value("user", user_name);

			handler.push(evento);
		}

		return correcto;
	}

	/**
	* Elimina un rol del sistema
	*
	* @param role_name Nombre del rol
	* @return True si se pudo eliminar el rol. False en caso contrario.
	*
	* @post Se envia un evento distribuido con los siguientes campos: 
	*		- type = (PortableInteger)MI_EVENT_TYPE  (@see MIEvent.h)
	*		- mi_type = (PortableInteger)REMOVE_ROLE
	*		- application = (char*)this->application
	*		- role = (char*)role_name
	*/
	public boolean remove_role(String role_name)
	{
		boolean correcto = mi_client.get_data_accessor().remove_role(application, role_name);
		
		if (correcto) //distribuir evento
		{
			MIEvent evento = new MIEvent();
			evento.member_value("mi_type", MIEvent.REMOVE_ROLE);
			evento.member_value("application", application);
			evento.member_value("role", role_name);

			handler.push(evento);
		}

		return correcto;
	}
	
	/**
	* Obtiene el rol actual de un usuario
	*
	* @param user_name Nombre del usuario
	* @return Rol actual del usuario
	*/
	public String user_actual_role(String user_name)
	{
		return mi_client.get_data_accessor().user_actual_role(application, user_name);
	}
	
	/**
	* Obtiene el rol actual del usuario
	*
	* @return Rol actual del usuario
	*/
	public String user_actual_role()
	{
		return role;
	}

	/**
	* Guarda la metainformacion del sistema de forma persistente
	*/
	public void commit()
	{
		mi_client.get_data_accessor().commit();
	}
}
